import * as Sentry from '@sentry/react';
import { Integrations } from '@sentry/tracing';
import { BrowserOptions as SentryOptions } from '@sentry/browser';

/**
 * sentry日志上报
 */
class SentryReport {
  public options: SentryOptions;

  private static instance: SentryReport;

  constructor(options: SentryOptions) {
    this.options = options;
  }

  static getInstance(options: SentryOptions) {
    if (!this.instance) {
      this.instance = new SentryReport(options);
      this.instance.init();
      this.instance.registerGlobalError();
    }
    return this.instance;
  }

  // 初始化
  public init() {
    const {
      dsn = '',
      release = '',
      environment = '',
      integrations = [new Integrations.BrowserTracing()],
      debug = false,
      tracesSampleRate = 1.0,
    } = this.options;
    Sentry.init({
      dsn,
      release,
      environment,
      debug,
      integrations,
      tracesSampleRate,
      ...this.options,
    });
  }

  public registerGlobalError() {
    // 全局监控资源加载错误
    window.addEventListener(
      'error',
      (event) => {
        const target = event.target || event.srcElement;
        const isElementTarget =
          target instanceof HTMLScriptElement || target instanceof HTMLLinkElement || target instanceof HTMLImageElement;
        if (!isElementTarget) {
          return false;
        }
        const url = (target as HTMLScriptElement | HTMLImageElement).src || (target as HTMLLinkElement).href;
        // 增加对资源加载错误的上报
        this.sendReport({
          error: new Error(`ResourceLoadError: ${url}`),
          type: 'resource load',
        });
      },
      true,
    );
  }

  /**
   * 自定义上报数据
   * @param errorInfo
   */
  public sendReport(errorInfo: AnyObject) {
    Sentry.withScope((scope) => {
      Object.keys(errorInfo).forEach((key) => {
        if (key !== 'error') {
          scope.setExtra(key, errorInfo[key]);
        }
      });
      Sentry.captureException(errorInfo.error || new Error(''));
    });
  }
}

export default SentryReport;
